home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue59 / ALFRESCO / AAWidWrd.pas next >
Encoding:
Pascal/Delphi Source File  |  2000-06-05  |  19.6 KB  |  747 lines

  1. {*********************************************************}
  2. {* AAWidWrd                                              *}
  3. {* Copyright (c) Julian M Bucknall 2000                  *}
  4. {* All rights reserved.                                  *}
  5. {*********************************************************}
  6. {* Algorithms Alfresco: Wide Word arithmetic             *}
  7. {*********************************************************}
  8.  
  9. {Note: this unit is released as freeware. In other words, you are free
  10.        to use this unit in your own applications, however I retain all
  11.        copyright to the code. JMB}
  12.  
  13. unit AAWidWrd;
  14.  
  15. interface
  16.  
  17. uses
  18.   SysUtils;
  19.  
  20. type
  21.   TaaWideWord = class
  22.     private
  23.       FDigitCount : integer;
  24.       FDigits     : PByteArray;
  25.       FPrimeTestCount : integer;
  26.     protected
  27.       procedure wwDivideByDigit(aDigit : byte);
  28.       function wwIsWitness(a, NMinus1 : TaaWideWord) : boolean;
  29.       procedure wwMultiplyByDigit(aDigit : byte);
  30.       function wwNormalize : integer;
  31.       procedure wwRecalcDigitCount;
  32.     public
  33.       constructor Create;
  34.       destructor Destroy; override;
  35.  
  36.       procedure SetToMax;
  37.       procedure SetToZero;
  38.       function IsDivBy3 : boolean;
  39.       function IsOne : boolean;
  40.       function IsZero : boolean;
  41.  
  42.       procedure Assign(x : TaaWideWord); overload;
  43.       procedure Assign(x : integer); overload;
  44.       function AsInteger : integer;
  45.  
  46.       function Compare(x : TaaWideWord) : integer;
  47.  
  48.       procedure Add(x : TaaWideWord);
  49.       procedure AddOne;
  50.       procedure SubOne;
  51.       procedure Subtract(x : TaaWideWord);
  52.       procedure Multiply(x : TaaWideWord);
  53.       procedure Divide(x : TaaWideWord;
  54.                        aRem : TaaWideWord);
  55.  
  56.       function IsPrime : boolean;
  57.       function BitCount : integer;
  58.       function GetBit(aInx : integer) : boolean;
  59.       procedure RandomPrime(aBitCount : integer);
  60.       procedure RandomRSAPrime(aBitCount : integer);
  61.  
  62.       procedure Print;
  63.  
  64.       property Digits : PByteArray read FDigits;
  65.       property DigitCount : integer read FDigitCount;
  66.       property PrimeTestCount : integer read FPrimeTestCount;
  67.   end;
  68.  
  69.  
  70. implementation
  71.  
  72. {====================================================================}
  73. function MaxI(x, y : integer) : integer;
  74. begin
  75.   if (x < y) then
  76.     Result := y
  77.   else
  78.     Result := x;
  79. end;
  80. {--------}
  81. procedure AddPrim(x, y : PByteArray; aCount : integer);
  82. var
  83.   Temp  : LongWord;
  84.   Carry : LongWord;
  85.   i     : integer;
  86. begin
  87.   Carry := 0;
  88.   for i := 0 to pred(aCount) do begin
  89.     Temp := x^[i] + y^[i] + Carry;
  90.     x^[i] := Temp mod 256;
  91.     Carry := Temp div 256;
  92.   end;
  93.   x^[aCount] := Carry;
  94. end;
  95. {--------}
  96. function ComparePrim(x, y : PByteArray; aCount : integer) : integer;
  97. var
  98.   i : integer;
  99. begin
  100.   for i := pred(aCount) downto 0 do begin
  101.     Result := longint(x^[i]) - y^[i];
  102.     if (Result <> 0) then
  103.       Exit;
  104.   end;
  105.   Result := 0;
  106. end;
  107. {--------}
  108. procedure MultiplyPrim(x, y    : PByteArray;
  109.                    var aXCount : integer;
  110.                        aYCount : integer);
  111. var
  112.   InxX    : integer;
  113.   InxY    : integer;
  114.   MaxX    : integer;
  115.   Carry   : LongWord;
  116.   Temp    : LongWord;
  117.   Result  : array [0..128] of byte;
  118. begin
  119.   {initialize the result}
  120.   FillChar(Result, sizeof(Result), 0);
  121.   {if either x or y had no digits, it was zero; the answer is zero}
  122.   if (aXCount = 0) or (aYCount = 0) then begin
  123.     Move(Result, x^, sizeof(Result));
  124.     aXCount := 0;
  125.     Exit;
  126.   end;
  127.   {for every Y digit we shall multiply by all the X digits}
  128.   MaxX := aXCount;
  129.   for InxY := 0 to pred(aYCount) do begin
  130.     {if the Y digit is zero there'll be nothing to do in this
  131.      loop, so only do work if it is non-zero}
  132.     if (y[InxY] <> 0) then begin
  133.       {start off with a carry of zero}
  134.       Carry := 0;
  135.       {for each X digit, we multiply it with the current Y digit, add
  136.        in the carry from the previous step, and add the current value
  137.        of the result digit}
  138.       for InxX := 0 to pred(MaxX) do begin
  139.         Temp := (LongWord(x[InxX]) * y[InxY]) +
  140.                 Result[InxX + InxY] + Carry;
  141.         {strip off the carry and set the result digit}
  142.         Result[InxX + InxY] := Temp mod 256;
  143.         Carry := Temp div 256;
  144.       end;
  145.       {make sure that any remaining carry is saved}
  146.       Result[InxY + MaxX] := Carry;
  147.     end;
  148.   end;
  149.   {return the answer}
  150.   Move(Result, x^, sizeof(Result));
  151.   {return the new number of digits}
  152.   inc(MaxX, aYCount);
  153.   while (x^[pred(MaxX)] = 0) do
  154.     dec(MaxX);
  155.   aXCount := MaxX;
  156. end;
  157. {--------}
  158. procedure PrintPrim(x : PByteArray; aLen : integer);
  159. var
  160.   i, j, k : integer;
  161. begin
  162.   j := 0;
  163.   k := 0;
  164.   for i := 0 to pred(aLen) do begin
  165.     write(Format('%.2x', [x^[i]]));
  166.     inc(j);
  167.     if (j = 4) then begin
  168.       inc(k);
  169.       if (k = 8) then begin
  170.         writeln;
  171.         k := 0;
  172.       end
  173.       else
  174.         write(' ');
  175.       j := 0;
  176.     end;
  177.   end;
  178.   writeln;
  179. end;
  180. {--------}
  181. function SubtractPrim(x, y : PByteArray; aCount : integer) : integer;
  182. var
  183.   Temp   : integer;
  184.   Borrow : integer;
  185.   i      : integer;
  186. begin
  187.   Borrow := 0;
  188.   for i := 0 to pred(aCount) do begin
  189.     Temp := x^[i] - (y^[i] + Borrow);
  190.     if (Temp < 0) then begin
  191.       inc(Temp, 256);
  192.       Borrow := 1;
  193.     end
  194.     else
  195.       Borrow := 0;
  196.     x^[i] := Temp;
  197.   end;
  198.   Result := Borrow;
  199. end;
  200. {====================================================================}
  201.  
  202.  
  203. {===TaaWideWord======================================================}
  204. constructor TaaWideWord.Create;
  205. begin
  206.   inherited Create;
  207.   FDigits := AllocMem(129); {enough for 1024 bits plus overflow}
  208.   FPrimeTestCount := 30;    {probability of not being prime: 2^(-30)}
  209. end;
  210. {--------}
  211. destructor TaaWideWord.Destroy;
  212. begin
  213.   if (FDigits <> nil) then
  214.     FreeMem(FDigits);
  215.   inherited Destroy;
  216. end;
  217. {--------}
  218. procedure TaaWideWord.Add(x : TaaWideWord);
  219. begin
  220.   FDigitCount := MaxI(DigitCount, x.DigitCount);
  221.   AddPrim(Digits, x.Digits, DigitCount);
  222.   if (Digits^[DigitCount] <> 0) then
  223.     inc(FDigitCount);
  224.   if (DigitCount > 128) then begin
  225.     SetToMax;
  226.     raise Exception.Create('TaaWideWord.Add: overflow')
  227.   end;
  228. end;
  229. {--------}
  230. procedure TaaWideWord.AddOne;
  231. var
  232.   Temp  : LongWord;
  233.   Carry : LongWord;
  234.   i     : integer;
  235. begin
  236.   Carry := 1;
  237.   i := 0;
  238.   while (Carry = 1) do begin
  239.     Temp := Digits^[i] + Carry;
  240.     Digits^[i] := Temp mod 256;
  241.     Carry := Temp div 256;
  242.     inc(i);
  243.   end;
  244. end;
  245. {--------}
  246. function TaaWideWord.AsInteger : integer;
  247. type
  248.   PInteger = ^integer;
  249. begin
  250.   Result := PInteger(Digits)^;
  251. end;
  252. {--------}
  253. procedure TaaWideWord.Assign(x : TaaWideWord);
  254. begin
  255.   FillChar(Digits^, 129, 0);
  256.   Move(x.Digits^, Digits^, x.DigitCount);
  257.   FDigitCount := x.DigitCount;
  258. end;
  259. {--------}
  260. procedure TaaWideWord.Assign(x : integer);
  261. type
  262.   PInteger = ^integer;
  263. begin
  264.   if (x < 0) then
  265.     raise Exception.Create('TaaWideWord.Assign: cannot convert negative number');
  266.   FillChar(Digits^, DigitCount, 0);
  267.   if (x = 0) then
  268.     FDigitCount := 0
  269.   else begin
  270.     PInteger(Digits)^ := x;
  271.     if (Digits^[3] <> 0) then
  272.       FDigitCount := 4
  273.     else if (Digits^[2] <> 0) then
  274.       FDigitCount := 3
  275.     else if (Digits^[1] <> 0) then
  276.       FDigitCount := 2
  277.     else
  278.       FDigitCount := 1;
  279.   end;
  280. end;
  281. {--------}
  282. function TaaWideWord.BitCount : integer;
  283. var
  284.   Test : byte;
  285. begin
  286.   if (DigitCount = 0) then
  287.     Result := 0
  288.   else begin
  289.     Result := pred(DigitCount) * 8;
  290.     Test := Digits^[pred(DigitCount)];
  291.     if (Test >= $80) then
  292.       inc(Result, 8)
  293.     else if (Test >= $40) then
  294.       inc(Result, 7)
  295.     else if (Test >= $20) then
  296.       inc(Result, 6)
  297.     else if (Test >= $10) then
  298.       inc(Result, 5)
  299.     else if (Test >= $08) then
  300.       inc(Result, 4)
  301.     else if (Test >= $04) then
  302.       inc(Result, 3)
  303.     else if (Test >= $02) then
  304.       inc(Result, 2)
  305.     else
  306.       inc(Result, 1);
  307.   end;
  308. end;
  309. {--------}
  310. function TaaWideWord.Compare(x : TaaWideWord) : integer;
  311. begin
  312.   if (DigitCount < x.DigitCount) then
  313.     Result := -1
  314.   else if (DigitCount > x.DigitCount) then
  315.     Result := 1
  316.   else
  317.     Result := ComparePrim(Digits, x.Digits, DigitCount);
  318. end;
  319. {--------}
  320. procedure TaaWideWord.Divide(x    : TaaWideWord;
  321.                              aRem : TaaWideWord);
  322. var
  323.   Divisor  : TaaWideWord;
  324.   Dividend : TaaWideWord;
  325.   Test     : TaaWideWord;
  326.   TestCompare : integer;
  327.   InxQ     : integer;
  328.   InxX     : integer;
  329.   Factor   : integer;
  330.   SigDigit : byte;
  331.   q        : longint;
  332. begin
  333.   {if the divisor (x) has no digits, it is zero: an error}
  334.   if (x.DigitCount = 0) then
  335.     raise Exception.Create('TaaWideWord.Divide: division by zero');
  336.   {if the divisor (x) is 1, the quotient (us) equals the dividend (us)
  337.    and the remainder is 0}
  338.   if x.IsOne then begin
  339.     aRem.SetToZero;
  340.     Exit;
  341.   end;
  342.   {if the dividend (us) has no digits, it is zero; the quotient (us)
  343.    and remainder must therefore both be zero}
  344.   if (DigitCount = 0) then begin
  345.     aRem.SetToZero;
  346.     Exit;
  347.   end;
  348.   {compare us to x}
  349.   TestCompare := Compare(x);
  350.   {if the dividend (us) is smaller than the divisor (x), the quotient
  351.    (us) is zero and the remainder equals the dividend (us)}
  352.   if (TestCompare < 0) then begin
  353.     aRem.Assign(Self);
  354.     SetToZero;
  355.     Exit;
  356.   end;
  357.   {last special test: if the dividend (us) and divisor (x) are the
  358.    same, the quotient (us) is 1 and the remainder 0}
  359.   if (TestCompare = 0) then begin
  360.     Assign(1);
  361.     aRem.SetToZero;
  362.     Exit;
  363.   end;
  364.   {if we reach this point we actually have to do some work: the
  365.    dividend is greater than the divisor, neither is zero, and the
  366.    divisor is not 1}
  367.  
  368.   {allocate and initialize some temporaries}
  369.   Test := nil;
  370.   Divisor := nil;
  371.   Dividend := nil;
  372.   try
  373.     Divisor := TaaWideWord.Create;
  374.     Divisor.Assign(x);
  375.     Dividend := TaaWideWord.Create;
  376.     Dividend.Assign(Self);
  377.     Test := TaaWideWord.Create;
  378.  
  379.     {after the division we shall be holding the quotient; make sure
  380.      we're zeroed out for now}
  381.     SetToZero;
  382.  
  383.     {make sure the most significant digit of the divisor is greater
  384.      than 128; retain the multiplicative factor to do that}
  385.     Factor := Divisor.wwNormalize;
  386.  
  387.     {multiply the dividend by the same factor}
  388.     if (Factor <> 1) then
  389.       Dividend.wwMultiplyByDigit(Factor);
  390.  
  391.     {if the most sigdigit of the dividend is greater than or equal to
  392.      that of the divisor, increment the number of digits in the
  393.      dividend; this'll help once we jump into the division itself}
  394.     if (Dividend.Digits^[pred(Dividend.DigitCount)] >=
  395.         Divisor.Digits^[pred(Divisor.DigitCount)]) then
  396.       inc(Dividend.FDigitCount);
  397.  
  398.     {Notes:
  399.      let's get some numbers nailed down:
  400.        n = number of digits in divisor
  401.        n+m+1 = number of digits in dividend (the first may be zero)
  402.        m+1 = number of digits in quotient (the first may be zero)
  403.        n = number of digits in remainder
  404.      we calculate the digits in the quotient from most to least
  405.        significant
  406.      the index of the most significant digit in the dividend is given
  407.        by InxX; it starts out as pred(DigitCount) and will reduce by
  408.        one each time through the loop
  409.      the index of the digits in the quotient is given by InxQ, InxQ
  410.        will vary from m down to 0 (ie, m+1 values)
  411.      note that InxQ will be the position of the start of the part of
  412.        the dividend we're looking at; in other words digits InxQ..InxX
  413.        of the dividend form the part of the dividend we're dividing by
  414.        the divisor
  415.     }
  416.  
  417.     {calculate the position of the most significant digit of both the
  418.      quotient and dividend}
  419.     InxQ := Dividend.DigitCount - Divisor.DigitCount;
  420.     FDigitCount := InxQ;
  421.     InxX := Dividend.DigitCount;
  422.     {get the most significant digit of the divisor}
  423.     SigDigit := Divisor.Digits^[pred(Divisor.DigitCount)];
  424.     {while we are still calculating quotient digits...}
  425.     while InxQ >= 0 do begin
  426.       {calculate our first estimate for this quotient digit q (it may
  427.        be too large of course but the final value will be within 2 of
  428.        this)}
  429.       q := ((LongWord(Dividend.Digits^[InxX]) * 256) +
  430.              Dividend.Digits^[InxX-1]) div SigDigit;
  431.       {refine q if necessary}
  432.       if (q <> 0) then begin
  433.         {it's only a digit so force it in range}
  434.         if (q >= 256) then
  435.           q := 255;
  436.         Test.Assign(Divisor);
  437.         Test.wwMultiplyByDigit(q);
  438.         while (ComparePrim(@Dividend.Digits^[InxQ],
  439.                            Test.Digits,
  440.                            Test.DigitCount+1) < 0) do begin
  441.           dec(q);
  442.           Test.Assign(Divisor);
  443.           Test.wwMultiplyByDigit(q);
  444.         end;
  445.       end;
  446.       {save this digit for the quotient}
  447.       Digits^[InxQ] := q;
  448.       {subtract}
  449.       if (q <> 0) then begin
  450.         SubtractPrim(@Dividend.Digits^[InxQ],
  451.                      Test.Digits,
  452.                      Test.DigitCount+1);
  453.       end;
  454.       {we've done this digit, now do the next}
  455.       dec(InxX);
  456.       dec(InxQ);
  457.     end;
  458.     {we now have the quotient, calculate the number of digits}
  459.     wwRecalcDigitCount;
  460.     {set up the remainder}
  461.     Dividend.wwRecalcDigitCount;
  462.     aRem.Assign(Dividend);
  463.     if (Factor <> 1) then
  464.       aRem.wwDivideByDigit(Factor);
  465.   finally
  466.     Divisor.Free;
  467.     Dividend.Free;
  468.     Test.Free;
  469.   end;
  470. end;
  471. {--------}
  472. function TaaWideWord.GetBit(aInx : integer) : boolean;
  473. const
  474.   Mask : array [0..7] of byte =
  475.            ($01, $02, $04, $08, $10, $20, $40, $80);
  476. var
  477.   ByteNum : integer;
  478.   BitNum : integer;
  479. begin
  480.   ByteNum := aInx div 8;
  481.   BitNum := aInx mod 8;
  482.   Result := (Digits^[ByteNum] and Mask[BitNum]) <> 0;
  483. end;
  484. {--------}
  485. function TaaWideWord.IsDivBy3 : boolean;
  486. var
  487.   i     : integer;
  488.   Count : integer;
  489.   AddIt : boolean;
  490. begin
  491.   Count := 0;
  492.   AddIt := true;
  493.   for i := pred(BitCount) downto 0 do begin
  494.     if GetBit(i) then
  495.       if AddIt then
  496.         inc(Count)
  497.       else
  498.         dec(Count);
  499.     AddIt := not AddIt;
  500.   end;
  501.   Result := (Count mod 3) = 0;
  502. end;
  503. {--------}
  504. function TaaWideWord.IsOne : boolean;
  505. begin
  506.   Result := (DigitCount = 1) and (Digits^[0] = 1);
  507. end;
  508. {--------}
  509. function TaaWideWord.IsPrime : boolean;
  510. var
  511.   a       : TaaWideWord;
  512.   NMinus1 : TaaWideWord;
  513.   TestNum : integer;
  514.   i       : integer;
  515. begin
  516.   {allocate temporaries}
  517.   a := nil;
  518.   NMinus1 := nil;
  519.   try
  520.     a := TaaWideWord.Create;
  521.     NMinus1 := TaaWideWord.Create;
  522.     NMinus1.Assign(Self);
  523.     NMinus1.SubOne;
  524.     {test PrimeTestCount times}
  525.     for TestNum := 1 to PrimeTestCount do begin
  526.       {set a to a random number between 1 and ourselves}
  527.       repeat
  528.         a.SetToZero;
  529.         a.FDigitCount := Random(DigitCount) + 1;
  530.         for i := 0 to pred(a.DigitCount) do
  531.           a.Digits^[i] := Random(256);
  532.         a.wwRecalcDigitCount;
  533.       until (not a.IsZero) and (Compare(a) > 0);
  534.       if wwIsWitness(a, NMinus1) then begin
  535.         Result := false;
  536.         Exit;
  537.       end;
  538.     end;
  539.     Result := true;
  540.   finally
  541.     a.Free;
  542.     NMinus1.Free;
  543.   end;
  544. end;
  545. {--------}
  546. function TaaWideWord.IsZero : boolean;
  547. begin
  548.   Result := DigitCount = 0;
  549. end;
  550. {--------}
  551. procedure TaaWideWord.Multiply(x : TaaWideWord);
  552. begin
  553.   if ((DigitCount + x.DigitCount) > 128) then begin
  554.     SetToMax;
  555.     raise Exception.Create('TaaWideWord.Multiply: overflow');
  556.   end;
  557.   MultiplyPrim(Digits, x.Digits, FDigitCount, x.DigitCount);
  558. end;
  559. {--------}
  560. procedure TaaWideWord.Print;
  561. begin
  562.   if IsZero then
  563.     writeln('zero')
  564.   else
  565.     PrintPrim(Digits, DigitCount);
  566. end;
  567. {--------}
  568. procedure TaaWideWord.RandomPrime(aBitCount : integer);
  569. var
  570.   ByteCount : integer;
  571.   i         : integer;
  572. begin
  573.   {fill with random digits}
  574.   ByteCount := (aBitCount + 7) div 8;
  575.   for i := pred(ByteCount) downto 0 do
  576.     Digits^[i] := Random(256);
  577.   FDigitCount := ByteCount;
  578.   {set the most and least significant bits}
  579.   Digits^[0] := Digits^[0] or $01;
  580.   Digits^[pred(ByteCount)] := Digits^[pred(ByteCount)] or $80;
  581.   {test for being a prime, if not continue adding 2 until we get one}
  582.   while not IsPrime do begin
  583.     AddOne;
  584.     AddOne;
  585.   end;
  586. end;
  587. {--------}
  588. procedure TaaWideWord.RandomRSAPrime(aBitCount : integer);
  589. begin
  590.   repeat
  591.     RandomPrime(aBitCount);
  592.     SubOne;
  593.   until not IsDivBy3;
  594.   AddOne;
  595. end;
  596. {--------}
  597. procedure TaaWideWord.SetToMax;
  598. begin
  599.   FillChar(Digits^, 128, $FF);
  600.   Digits^[128] := 0;
  601.   FDigitCount := 128;
  602. end;
  603. {--------}
  604. procedure TaaWideWord.SetToZero;
  605. begin
  606.   FillChar(Digits^, 129, 0);
  607.   Digits^[128] := 0;
  608.   FDigitCount := 0;
  609. end;
  610. {--------}
  611. procedure TaaWideWord.SubOne;
  612. var
  613.   Done : boolean;
  614.   i    : integer;
  615. begin
  616.   Done := false;
  617.   i := 0;
  618.   while not Done do begin
  619.     if (Digits^[i] = 0) then begin
  620.       Digits^[i] := 255;
  621.       inc(i);
  622.     end
  623.     else begin
  624.       dec(Digits^[i]);
  625.       Done := true;
  626.     end;
  627.   end;
  628. end;
  629. {--------}
  630. procedure TaaWideWord.Subtract(x : TaaWideWord);
  631. var
  632.   Borrow : integer;
  633. begin
  634.   if (DigitCount < x.DigitCount) then
  635.     Borrow := 1
  636.   else
  637.     Borrow := SubtractPrim(Digits, x.Digits, DigitCount);
  638.   if (Borrow <> 0) then
  639.     raise Exception.Create('TaaWideWord.Subtract: negative result');
  640.   wwRecalcDigitCount;
  641. end;
  642. {--------}
  643. procedure TaaWideWord.wwDivideByDigit(aDigit : byte);
  644. var
  645.   Remainder : LongWord;
  646.   Temp      : LongWord;           
  647.   i         : integer;
  648. begin
  649.   Remainder := 0;
  650.   for i := pred(DigitCount) downto 0 do begin
  651.     Temp := (Remainder * 256) + Digits^[i];
  652.     Digits^[i] := Temp div aDigit;
  653.     Remainder := Temp mod aDigit;
  654.   end;
  655. end;
  656. {--------}
  657. function TaaWideWord.wwIsWitness(a, NMinus1 : TaaWideWord) : boolean;
  658. var
  659.   d : TaaWideWord;
  660.   Rem : TaaWideWord;
  661.   x : TaaWideWord;
  662.   i : integer;
  663. begin
  664.   {allocate temporaries}
  665.   d := nil;
  666.   x := nil;
  667.   Rem := nil;
  668.   try
  669.     d := TaaWideWord.Create;
  670.     x := TaaWideWord.Create;
  671.     Rem := TaaWideWord.Create;
  672.     d.Assign(1);
  673.     {we're going to be calculating a^(n-1) mod n by the square and
  674.      multiply method}
  675.     for i := pred(NMinus1.BitCount) downto 0 do begin
  676.       x.Assign(d);
  677.       d.Multiply(d);
  678.       d.Divide(Self, Rem);
  679.       if (Rem.DigitCount > Self.DigitCount) then
  680.         writeln('error');
  681.       d.Assign(Rem);
  682.       if d.IsOne then begin
  683.         if (not x.IsOne) and (x.Compare(NMinus1) <> 0) then begin
  684.           Result := true;
  685.           Exit;
  686.         end;
  687.       end;
  688.       if NMinus1.GetBit(i) then begin
  689.         d.Multiply(a);
  690.         d.Divide(Self, Rem);
  691.         if (Rem.DigitCount > Self.DigitCount) then
  692.           writeln('error');
  693.         d.Assign(Rem);
  694.       end;
  695.     end;
  696.     Result := not d.IsOne;
  697.   finally
  698.     d.Free;
  699.     x.Free;
  700.     Rem.Free;
  701.   end;
  702. end;
  703. {--------}
  704. procedure TaaWideWord.wwMultiplyByDigit(aDigit : byte);
  705. var
  706.   i    : integer;
  707.   Temp : LongWord;
  708.   Carry: LongWord;
  709. begin
  710.   if (aDigit <> 1) then begin
  711.     Carry := 0;
  712.     for i := 0 to pred(DigitCount) do begin
  713.       Temp := (LongWord(Digits^[i]) * aDigit) + Carry;
  714.       Digits^[i] := Temp mod 256;
  715.       Carry := Temp div 256;
  716.     end;
  717.     if (Carry <> 0) then begin
  718.       Digits^[DigitCount] := Carry;
  719.       inc(FDigitCount);
  720.     end;
  721.   end;
  722. end;
  723. {--------}
  724. function TaaWideWord.wwNormalize : integer;
  725. var
  726.   Test     : byte;
  727. begin
  728.   Test := Digits^[pred(DigitCount)];
  729.   Result := 1;
  730.   while (Test < 128) do begin
  731.     Result := Result * 2;
  732.     Test := Test * 2;
  733.   end;
  734.   if Result <> 1 then
  735.     wwMultiplyByDigit(Result);
  736. end;
  737. {--------}
  738. procedure TaaWideWord.wwRecalcDigitCount;
  739. begin
  740.   while (DigitCount > 0) and (Digits^[pred(DigitCount)] = 0) do
  741.     dec(FDigitCount);
  742. end;
  743. {====================================================================}
  744.  
  745. end.
  746.  
  747.